/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.explorer.propertysheet;
import java.awt.Component;
import java.awt.BorderLayout;
import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
// TO DO:
// 1. add PREF_XXX constants
// 2. implement PREF_READ_ONLY
// 3. improve updateComponent method
// 4. i18n
/** Visual Java Bean for editing of properties. It takes the model
* and represents the property editor for it.
*
* @author Jaroslav Tulach, Petr Hamernik, Jan Jancura
*/
public class PropertyPanel extends JComponent {
/**
* Constant defining preferences in displaying of value.
* Value should be displayed in read-only mode.
*/
public static final int PREF_READ_ONLY = 0x0001;
/**
* Constant defining preferences in displaying of value.
* Value should be displayed in custom editor.
*/
public static final int PREF_CUSTOM_EDITOR = 0x0002;
/**
* Constant defining preferences in displaying of value.
* Value should be displayed in editor only.
*/
public static final int PREF_INPUT_STATE = 0x0004;
/** Name of the 'preferences' property */
public static final String PROP_PREFERENCES = "preferences"; // NOI18N
/** Name of the 'model' property */
public static final String PROP_MODEL = "model"; // NOI18N
/** Name of the read-only property 'propertyEditor' */
public static final String PROP_PROPERTY_EDITOR = "propertyEditor"; // NOI18N
/** Static instance of empty PropertyModel. */
private static PropertyModel EMPTY_MODEL = new EmptyModel();
/** Holds value of property preferences. */
private int preferences = 0;
/** Holds value of property model. */
private PropertyModel model;
/** Listener for the model and prop.editor properties changes. */
private PropertyChangeListener listener;
/** Current property editor */
private PropertyEditor editor;
/** Status flag - prevention of cycle in fires properties. */
private boolean ignoreModelEvent = false;
/** Status flag - prevention of cycle in fires properties. */
private boolean ignoreEditorEvent = false;
/** Creates new PropertyPanel with the empty DefaultPropertyModel
*/
public PropertyPanel () {
this (EMPTY_MODEL, 0);
}
/** Creates new PropertyPanel with DefaultPropertyModel
* @param bean The instance of bean
* @param propertyName The name of the property to be displayed
*/
public PropertyPanel (
Object bean,
String propertyName,
int preferences
) {
this (
new DefaultPropertyModel (bean, propertyName),
preferences
);
}
/** Creates new PropertyPanel
* @param model The model for displaying
*/
public PropertyPanel (
PropertyModel model,
int preferences
) {
this.model = model;
this.preferences = preferences;
listener = new PropertyL ();
setLayout (new BorderLayout ());
model.addPropertyChangeListener (listener);
updateEditor ();
updateComponent ();
}
/** Getter for property preferences.
* @return Value of property preferences.
*/
public int getPreferences () {
return preferences;
}
/* Setter for visual preferences in displaying
* of the value of the property.
* @param pref PREF_XXXX constants
*/
public void setPreferences (int preferences) {
int oldPreferences = this.preferences;
this.preferences = preferences;
updateComponent ();
firePropertyChange(
PROP_PREFERENCES,
new Integer (oldPreferences),
new Integer (preferences)
);
}
/** Getter for property model.
* @return Value of property model.
*/
public PropertyModel getModel() {
return model;
}
/** Setter for property model.
*@param model New value of property model.
*/
public void setModel(PropertyModel model) {
PropertyModel oldModel = this.model;
this.model = model;
oldModel.removePropertyChangeListener(listener);
model.addPropertyChangeListener(listener);
updateEditor();
updateComponent();
firePropertyChange (PROP_MODEL, oldModel, model);
}
/** Update the current property editor depending on the model.
*/
private void updateEditor() {
PropertyEditor oldEditor = editor;
// find new editor
editor = null;
Class editorClass = model.getPropertyEditorClass();
if (editorClass != null) {
try {
editor = (PropertyEditor) editorClass.newInstance();
}
catch (Exception e) {
if (Boolean.getBoolean("org.netbeans.exceptions")) // NOI18N
e.printStackTrace();
}
}
if (editor == null) {
Class propertyTypeClass = model.getPropertyType();
if (propertyTypeClass != null)
editor = PropertyEditorManager.findEditor(propertyTypeClass);
} else {
try {
editor.setValue(model.getValue());
}
catch (InvocationTargetException e) {
if (Boolean.getBoolean("org.netbeans.exceptions")) // NOI18N
e.printStackTrace();
}
}
// listener add and remove
if (oldEditor != null)
oldEditor.removePropertyChangeListener(listener);
if (editor != null)
editor.addPropertyChangeListener(listener);
// fire the change
firePropertyChange(PROP_PROPERTY_EDITOR, oldEditor, editor);
}
/**
* Getter for current property editor depending on the model.
* It could be <CODE>null</CODE> if there is not possible
* to obtain property editor for the current model.
*
* @return the property editor or <CODE>null</CODE>
*/
public PropertyEditor getPropertyEditor() {
return editor;
}
/** Update the content of this Panel depending on model.
*/
private void updateComponent() {
removeAll();
if (editor == null) {
add (new JLabel (NbBundle.getBundle (PropertyPanel.class).
getString ("CTL_No_property_editor")), BorderLayout.CENTER
);
return;
}
Component c = null;
if ((getPreferences () & PREF_CUSTOM_EDITOR) != 0)
c = editor.getCustomEditor();
if (c == null) {
c = new PropertyDisplayer ();
((PropertyDisplayer) c).setValueAsProperty (new Property (model.getPropertyType ()));
if ((getPreferences () & PREF_INPUT_STATE) == 0) {
((PropertyDisplayer) c).setInputState (false);
((PropertyDisplayer) c).setSwitchAutomatically (true);
} else {
((PropertyDisplayer) c).setSwitchAutomatically (false);
}
}
if (c == null)
c = new JLabel (NbBundle.getBundle (PropertyPanel.class).
getString ("CTL_No_custom_editor")
);
add (c, BorderLayout.CENTER);
try {
editor.setValue(model.getValue());
}
catch (InvocationTargetException e) {
if (Boolean.getBoolean("org.netbeans.exceptions")) // NOI18N
e.printStackTrace();
}
}
// innerclasses ..............................................................
/** Property change listener for the editor and the model.
*/
private class PropertyL implements PropertyChangeListener {
/** Property was changed. */
public void propertyChange(PropertyChangeEvent evt) {
// MODEL changes
if (!ignoreModelEvent && (evt.getSource() == model)) {
if (PropertyModel.PROP_VALUE.equals(evt.getPropertyName())) {
if (editor != null) {
try {
ignoreEditorEvent = true;
editor.setValue(model.getValue());
}
catch (InvocationTargetException e) {
if (Boolean.getBoolean("org.netbeans.exceptions")) // NOI18N
e.printStackTrace();
}
finally {
ignoreEditorEvent = false;
}
}
}
}
// EDITOR changes
else if ((!ignoreEditorEvent) && (editor != null) && (evt.getSource() == editor)) {
try {
ignoreModelEvent = true;
model.setValue(editor.getValue());
}
catch (InvocationTargetException e) {
if (Boolean.getBoolean("org.netbeans.exceptions")) // NOI18N
e.printStackTrace();
}
finally {
ignoreModelEvent = false;
}
}
}
}
/** Empty implementation of the PropertyModel interface.
*/
private static class EmptyModel implements PropertyModel {
/** @return <CODE>null</CODE> */
public Object getValue() throws InvocationTargetException {
return null;
}
/** Does nothing. */
public void setValue(Object v) throws InvocationTargetException {
}
/** @return <CODE>Object.class</CODE> */
public Class getPropertyType() {
return Object.class;
}
/** @return <CODE>null</CODE> */
public Class getPropertyEditorClass() {
return null;
}
/** Does nothing. */
public void addPropertyChangeListener(PropertyChangeListener l) {
}
/** Does nothing. */
public void removePropertyChangeListener(PropertyChangeListener l) {
}
}
private class Property extends Node.Property {
/** Creates property. */
Property (Class clazz) {
super (clazz);
}
/** Gets value from model. */
public Object getValue () throws InvocationTargetException {
return model.getValue ();
}
/** Sets value for model. */
public void setValue (Object val) throws InvocationTargetException {
model.setValue (val);
}
/** Returns PropertyEditor. */
public PropertyEditor getPropertyEditor () {
return editor;
}
/** @return <CODE>true</CODE>. */
public boolean canRead () {
return true;
}
/** @return PREF_READ_ONLY value. */
public boolean canWrite () {
return (getPreferences () & PREF_READ_ONLY) == 0;
}
}
}
/*
* Log
* 5 Gandalf 1.4 1/12/00 Ian Formanek NOI18N
* 4 Gandalf 1.3 1/9/00 Jan Jancura [Petr H.] Used PropCh.
* supp. form superclass
* 3 Gandalf 1.2 12/9/99 Jan Jancura PropertyPanel
* implementation + Bug 3961
* 2 Gandalf 1.1 12/2/99 Petr Nejedly setValue for editor
* earlier, enable forwarding property chages in finally{}
* 1 Gandalf 1.0 11/25/99 Petr Hamernik
* $
*/